﻿#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;

namespace GameToolkit
{

    [DisallowMultipleComponent]
    public sealed class MaterialBlock : MonoBehaviour, ICbufferBlock
    {
        [System.Serializable]
        public struct Keyword
        {
            public string name;
            public bool enabled;
        }

        [SerializeField]
        Keyword[] m_Keywords;

        [SerializeField, HideInInspector]
        private MaterialInstance m_MaterialInstance;

        [SerializeField, HideInInspector]
        private MaterialInstance.Property[] m_CBufferValues;

        MaterialInstance mUsingInstance;
        MaterialInstance mOverrideInstance;
        MaterialGroupOverrider mOverrider;
        // 覆盖材质属性
        //bool mOverrideMaterial;

        public MaterialInstance sharedMaterialInstance
        {
            get { return m_MaterialInstance; }
            set
            {
                if (m_MaterialInstance != value)
                {
                    m_MaterialInstance = value;
                    if (mOverrider != null)
                    {
                        var use = mOverrideInstance == null ? m_MaterialInstance : mOverrideInstance;
                        if (use != mUsingInstance)
                        {
                            if (mUsingInstance != null)
                                mUsingInstance.OnValidateMaterial -= OnMaterialInstanceDirty;
                            mUsingInstance = use;
                            if (mUsingInstance != null)
                                mUsingInstance.OnValidateMaterial += OnMaterialInstanceDirty;
                            mOverrider.SetDirty(transform);
                        }
                    }
                }
            }
        }

        public MaterialInstance materialInstance
        {
            get { return mOverrideInstance == null ? m_MaterialInstance : mOverrideInstance; }
            set
            {
                if (mOverrideInstance != value)
                {
                    mOverrideInstance = value;
                    if (mOverrider != null)
                    {
                        var use = mOverrideInstance == null ? m_MaterialInstance : mOverrideInstance;
                        if (use != mUsingInstance)
                        {
                            if (mUsingInstance != null)
                                mUsingInstance.OnValidateMaterial -= OnMaterialInstanceDirty;
                            mUsingInstance = use;
                            if (mUsingInstance != null)
                                mUsingInstance.OnValidateMaterial += OnMaterialInstanceDirty;
                            mOverrider.SetDirty(transform);
                        }
                    }
                }
            }
        }

        void ICbufferBlock.OnBinding(MaterialGroupOverrider overrider)
        {
            //Debug.LogFormat(this, "{0} bind to {1}", this, overrider);
            mOverrider = overrider;
            var use = materialInstance;
            if (use != mUsingInstance)
            {
                if (mUsingInstance != null)
                    mUsingInstance.OnValidateMaterial -= OnMaterialInstanceDirty;
                mUsingInstance = use;
                if (mUsingInstance != null)
                    mUsingInstance.OnValidateMaterial += OnMaterialInstanceDirty;
                //mOverrider.SetDirty(transform);
            }
        }

        void ICbufferBlock.OnUnbinding(MaterialGroupOverrider overrider)
        {
            //Debug.LogFormat(this, "{0} unbind from {1}", this, overrider);
            if (mOverrider == overrider)
            {
                mOverrider = null;
                if (mUsingInstance != null)
                    mUsingInstance.OnValidateMaterial -= OnMaterialInstanceDirty;
            }
        }

        void ICbufferBlock.OnSetupMaterial(Renderer renderer, int materialIndex, IMaterialPropertyBlock block)
        {
            if (m_Keywords != null)
            {
                for (int i = 0; i < m_Keywords.Length; i++)
                {
                    var key = m_Keywords[i];
                    if (!string.IsNullOrEmpty(key.name))
                    {
                        if (key.enabled)
                            block.EnableKeyword(key.name);
                        else
                            block.DisableKeyword(key.name);
                    }
                }
            }
            var inst = materialInstance;
            if (inst != null)
            {
                inst.SetMaterial(block);
            }
            else if (m_CBufferValues != null)
            {
                for (int i = 0; i < m_CBufferValues.Length; i++)
                {
                    MaterialInstance.SetValue(block, m_CBufferValues[i]);
                }
            }
        }


        void OnMaterialInstanceDirty()
        {
            if (mOverrider != null)
                mOverrider.SetDirty(transform);
        }

#if UNITY_EDITOR
        private void OnValidate()
        {
            if (mOverrider != null)
            {
                var use = materialInstance;
                if (use != mUsingInstance)
                {
                    if (mUsingInstance != null)
                        mUsingInstance.OnValidateMaterial -= OnMaterialInstanceDirty;
                    mUsingInstance = use;
                    if (mUsingInstance != null)
                        mUsingInstance.OnValidateMaterial += OnMaterialInstanceDirty;
                }
                mOverrider.SetDirty(transform);
            }
        }

#endif


    }
}